package com.zy.service.sys.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import tk.mybatis.mapper.entity.Example;

import com.zy.dao.sys.RoleDao;
import com.zy.dao.sys.RoleResourceDao;
import com.zy.entity.enums.StatusEnum;
import com.zy.entity.sys.Role;
import com.zy.entity.sys.RoleResource;
import com.zy.pojo.annotation.RedisCacheMethod;
import com.zy.pojo.constants.Constant;
import com.zy.pojo.exceptions.ExceptionEnum;
import com.zy.pojo.exceptions.ServiceException;
import com.zy.service.base.impl.BaseServiceImpl;
import com.zy.service.sys.RoleService;
import com.zy.utils.DateUtil;
import com.zy.utils.ValidUtil;
import com.zy.utils.tree.BaseTree;
import com.zy.utils.tree.RoleTree;
import com.zy.utils.tree.TreeBean;
import com.zy.utils.tree.TreeUtil;

/**
 * 
 * @author liu
 * @date 2016年8月6日
 *
 */
@Service("roleService")
public class RoleServiceImpl extends BaseServiceImpl<Role> implements RoleService {

	@Autowired
	private RoleDao roleDao;
	@Autowired
	private RoleResourceDao roleResourceDao;

	@RedisCacheMethod(methodName = "deleteAuthorizationCacheByRoleId", paramNames = { "id" })
	@Override
	public void grant(long id, Set<Long> resourceIds) {
		RoleResource roleResource = new RoleResource();
		roleResource.setRoleId(id);
		roleResourceDao.remove(roleResource);
		if (ValidUtil.isNotEmpty(resourceIds)) {
			this.roleResourceDao.saveRoleResourceList(id, resourceIds);
		}
	}

	@Override
	public void saveRole(Role role) {
		if (this.roleDao.getCount(new Role(role.getRoleName())) > 0) {
			throw new ServiceException(ExceptionEnum.ROLENAME_EXISTED);
		}
		long time = DateUtil.getTime();
		role.setCreateTime(time);
		role.setModifyTime(time);
		role.setStatus(StatusEnum.NORMAL.getValue());
		this.roleDao.save(role);
	}

	@RedisCacheMethod(methodName = "deleteAuthorizationCacheByRoleId", paramNames = { "id" })
	@Override
	public void updateRole(long id, Role role) {
		Role nameRole = this.roleDao.get(new Role(role.getRoleName()));
		if (nameRole != null && nameRole.getId().longValue() != id) {
			throw new ServiceException(ExceptionEnum.ROLENAME_EXISTED);
		}
		role.setModifyTime(DateUtil.getTime());
		this.roleDao.updateByPrimaryKeySelective(role);
	}

	@RedisCacheMethod(methodName = "deleteAuthorizationCacheByRoleId", paramNames = { "id" })
	@Override
	public void removeRole(long id) {
		if (this.roleDao.getByPrimaryKey(id).getRoleName().equals(Constant.ADMIN)) {
			throw new ServiceException(ExceptionEnum.ADMIN_NOT_ALLOW_DELETE);
		}
		try {
			RoleResource roleResource = new RoleResource();
			roleResource.setRoleId(id);
			this.roleResourceDao.remove(roleResource);
			this.roleDao.removeByPrimaryKey(id);
		} catch (Exception e) {
			log.info(ExceptionUtils.getStackTrace(e));
			Role role = new Role();
			role.setId(id);
			role.setModifyTime(DateUtil.getTime());
			role.setStatus(StatusEnum.DELETE.getValue());
			this.roleDao.updateByPrimaryKeySelective(role);
		}
	}

	@RedisCacheMethod(methodName = "deleteAuthorizationCacheByRoleId", paramNames = { "id" })
	@Override
	public void recover(long id) {
		Role role = new Role();
		role.setId(id);
		role.setModifyTime(DateUtil.getTime());
		role.setStatus(StatusEnum.NORMAL.getValue());
		this.roleDao.updateByPrimaryKeySelective(role);
	}

	@RedisCacheMethod(methodName = "deleteAuthorizationCacheByRoleId", paramNames = { "id" })
	@Override
	public void freeze(long id) {
		if (this.roleDao.getByPrimaryKey(id).getRoleName().equals(Constant.ADMIN)) {
			throw new ServiceException(ExceptionEnum.ADMIN_NOT_ALLOW_FREEZE);
		}
		Role role = new Role();
		role.setId(id);
		role.setModifyTime(DateUtil.getTime());
		role.setStatus(StatusEnum.FREEZE.getValue());
		this.roleDao.updateByPrimaryKeySelective(role);
	}

	@RedisCacheMethod(methodName = "deleteAuthorizationCacheByRoleId", paramNames = { "id" })
	@Override
	public void unfreeze(long id) {
		Role role = new Role();
		role.setId(id);
		role.setModifyTime(DateUtil.getTime());
		role.setStatus(StatusEnum.NORMAL.getValue());
		this.roleDao.updateByPrimaryKeySelective(role);
	}

	@Override
	public List<Long> listIdByUserId(long userId) {
		return this.roleDao.listIdByUserId(userId);
	}

	@Override
	public BaseTree roleTree(Long userId) {
		BaseTree root = new BaseTree();
		root.setId("0");
		root.setParentId("-1");
		List<Long> roleIds = null;
		Set<Long> set = new HashSet<Long>();
		if(!Objects.equals(userId,1L)){
			roleIds = listIdByUserId(userId);
			List<TreeBean> listRole  = TreeUtil.conversion(roleDao.listAll());
			roleIds.forEach(id->{
				TreeBean bean = new TreeBean();
				BeanUtils.copyProperties(roleDao.getByPrimaryKey(id),bean);
				Long parentId  =TreeUtil.getParent(listRole,bean).getId();
				List<Long> ids = new ArrayList<Long>();
				ids.add(parentId);
				ids =TreeUtil.getRoleChildList( listRole,parentId,ids );
				ids.forEach(i->{
					set.add(i);
				});

			});

		}
		List<Role> roles = roleDao.roleTree(set);
		List<RoleTree> rootNode = new ArrayList<RoleTree>();
		roles.forEach(r->{
			RoleTree node = new RoleTree();
			BeanUtils.copyProperties(r,node);
			node.setId(r.getId()+"");
			if(Objects.isNull(r.getParentId())) node.setParentId("0");
			else
				node.setParentId(r.getParentId() + "");
			rootNode.add(node);
		});
		TreeUtil.appendChildren(root, rootNode);
		return root;
	}

	@Override
	public List<Role> list(Long userId) {
		Set<Long> set = new HashSet<Long>();
		Example example = new Example(Role.class);
		Example.Criteria c = example.createCriteria();
			List<Long> roleIds = null;
			if(!Objects.equals(userId,1L)){
				roleIds = listIdByUserId(userId);
				List<TreeBean> listRole  = TreeUtil.conversion(roleDao.listAll());
				roleIds.forEach(id->{
					List<Long> ids = new ArrayList<Long>();
					ids =TreeUtil.getRoleChildList( listRole,id,ids );
					ids.forEach(i->{
						set.add(i);
					});
				});
			}
		List<Long> selectIds = set.stream().collect(Collectors.toList());
		if(selectIds.size()>0){
			c.andIn("id",selectIds);
		}
		c.andEqualTo("status", StatusEnum.NORMAL.getValue());
		return this.roleDao.listByExample(example);
	}

	@Override
	public List<Role> getRoles() {
		Example ex = new Example(Role.class);
		ex.createCriteria().andNotEqualTo("id",1);
		return roleDao.listByExample(ex);
	}

//	/**
//	 * 获取子所有节点
//	 * @param roleList
//	 * @param pid
//	 * @param ids
//	 * @return
//	 */
//	private   List<Long> getRoleChildList( List<Role> roleList, Long pid,List<Long> ids ){
//		Role r = roleList.stream().filter(role -> role.getParentId()==pid).findFirst().orElse(null);
//		if(Objects.isNull(r)) return ids;
//		else
//        ids.add(r.getId());
//		return getRoleChildList(roleList,r.getId(),ids);
//	}
//
//	/**
//	 * 获取父节点
//	 * @param roleList
//	 * @param role
//	 * @return
//	 */
//	private Role getParent( List<Role> roleList, Role role){
//		Role r = roleList.stream().filter(
//				rs ->rs.getId()== role.getParentId()).findFirst().orElse(role);
//		if(Objects.isNull(r)) return r;
//		else
//		return getParent(roleList,r);
//	}

}
